package server;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * Minicat主类
 */
public class Bootstrap {

    private int port = 8080;

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    /**
     * 程序开始
     */
    public void start() throws IOException {

        // 加载web.xml配置文件
        loadServlet();

        // 定义线程池
        int corePoolSize = 10;
        int maximumPoolSize = 100;
        long keepAliveTime = 100L;
        TimeUnit unit = TimeUnit.SECONDS;
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<Runnable>(50);
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
            corePoolSize,
            maximumPoolSize,
            keepAliveTime,
            unit,
            workQueue,
            threadFactory,
            handler
        );

        ServerSocket serverSocket = new ServerSocket(port);
        System.out.println("========>>>Minicat start on port:" + port);

        /**
         * v1.0 版本
         * 需求：浏览器请求http://localhost:8080，返回一个固定的字符串到页面"Hello Minicat!"
         */
//        while (true) {
//            Socket socket = serverSocket.accept();
//            // 有了 socket，接收到请求，获取输出流
//            OutputStream outputStream = socket.getOutputStream();
//            String data = "Hello Minicat!";
//            String responseText = HttpProtocolUtil.getHttpHeader200(data.length()) + data;
//            outputStream.write(responseText.getBytes());
//            socket.close();
//        }

        /**
         * 完成Minicat 2.0版本
         * 需求：将请求信息封装成request对象及将响应信息封装成response对象，返回html静态页面
         */
//        while (true) {
//            Socket socket = serverSocket.accept();
//            // 有了 socket，接收到请求，获取输入流
//            InputStream inputStream = socket.getInputStream();
//
//            // 封装Request对象和Response对象
//            Request request = new Request(inputStream);
//            Response response = new Response(socket.getOutputStream());
//
//            // 静态资源处理
//            response.outputHtml(request.getUrl());
//
//            socket.close();
//        }

        /**
         * 完成Minicat 3.0版本
         * 需求：处理动态资源请求
         */
//        while (true) {
//            Socket socket = serverSocket.accept();
//            // 有了 socket，接收到请求，获取输入流
//            InputStream inputStream = socket.getInputStream();
//
//            // 封装Request对象和Response对象
//            Request request = new Request(inputStream);
//            Response response = new Response(socket.getOutputStream());
//
//            // 静态资源处理
//            if (servletMap.get(request.getUrl()) == null) {
//                response.outputHtml(request.getUrl());
//            }else {// 动态资源servlet处理
//                HttpServlet httpServlet = servletMap.get(request.getUrl());
//                httpServlet.service(request, response);
//            }
//
//            socket.close();
//        }

        /**
         * 使用多线程改造
         */
//        while (true) {
//            Socket socket = serverSocket.accept();
//            ServletProcessor servletProcessor = new ServletProcessor(socket, servletMap);
//            servletProcessor.start();
//        }

        System.out.println("===========>>>使用线程池改造");
        /**
         * 使用线程池改造
         */
        while (true) {
            Socket socket = serverSocket.accept();
            ServletProcessor servletProcessor = new ServletProcessor(socket, servletMap);
            threadPoolExecutor.execute(servletProcessor);
        }
    }

    private Map<String, HttpServlet> servletMap = new HashMap<>();

    /**
     * 加载配置文件：web.xml
     */
    private void loadServlet() {
        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("web.xml");
        SAXReader saxReader = new SAXReader();
        try {
            // 读取成文档
            Document document = saxReader.read(resourceAsStream);
            // 获取根元素
            Element rootElement = document.getRootElement();
            // 获取servlet元素
            List<Element> selectNodes = rootElement.selectNodes("//servlet");
            for (Element selectNode : selectNodes) {
                // <servlet-name>
                Element servletNameElement = (Element) selectNode.selectSingleNode("servlet-name");
                // <servlet-class>
                Element servletClassElement = (Element) selectNode.selectSingleNode("servlet-class");

                String servletName = servletNameElement.getStringValue();
                String servletClass = servletClassElement.getStringValue();

                // 获取匹配的url-pattern
                Element servletMappingElement = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");
                Element urlPatternElement = (Element) servletMappingElement.selectSingleNode("url-pattern");
                String urlPattern = urlPatternElement.getStringValue();

                // 将urlPattern和servletClass关联
                servletMap.put(urlPattern, (HttpServlet) Class.forName(servletClass).newInstance());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * Minicat启动入口
     * @param args
     */
    public static void main(String[] args) throws ClassNotFoundException, MalformedURLException {
        Bootstrap bootstrap = new Bootstrap();
        try {
            bootstrap.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
